#include "sk6812_spi.h"

// 灯条显存SPI数据缓存
uint8_t gWs2812bDat_SPI[WS2812B_AMOUNT * 24] = {0};
// 灯条显存
tWs2812bCache_TypeDef gWs2812bDat[WS2812B_AMOUNT] = {
    0x00, 0x00, 0x00, // 黑色
    0xFF, 0x00, 0x00, // 红色
    0xFF, 0x80, 0x00, // 橙色
    0xFF, 0xFF, 0x00, // 黄色
    0x80, 0xFF, 0x00, // 黄绿色
    0x00, 0xFF, 0x00, // 绿色
    0x00, 0xFF, 0x80, // 青绿色
    0x00, 0xFF, 0xFF, // 青色
    0x00, 0x80, 0xFF, // 天蓝色
    0x00, 0x00, 0xFF, // 蓝色
    0x80, 0x00, 0xFF, // 蓝紫色
    0xFF, 0x00, 0xFF, // 紫色
    0xFF, 0x00, 0x80, // 紫红色
    0x80, 0x80, 0x80, // 灰色
    0xFF, 0xFF, 0xFF // 白色

};


// 将指定LED的RGB颜色值转换为WS2812B协议要求的SPI数据格式，并存储到SPI发送缓冲区中。
void WS2812b_Set(uint16_t Ws2b812b_NUM, uint8_t r, uint8_t g, uint8_t b)
{
    uint8_t *pR = &gWs2812bDat_SPI[(Ws2b812b_NUM) * 24 + 8]; // 设置单个不同颜色分量的起始位置。Ws2b812b_NUM是第0颗。
    uint8_t *pG = &gWs2812bDat_SPI[(Ws2b812b_NUM) * 24];
    uint8_t *pB = &gWs2812bDat_SPI[(Ws2b812b_NUM) * 24 + 16];

    for (uint8_t i = 0; i < 8; i++)
    {
        if (g & 0x80)
        {
            *pG = CODE_1;
        }
        else
        {
            *pG = CODE_0;
        }
        if (r & 0x80)
        {
            *pR = CODE_1;
        }
        else
        {
            *pR = CODE_0;
        }
        if (b & 0x80)
        {
            *pB = CODE_1;
        }
        else
        {
            *pB = CODE_0;
        }
        r <<= 1;
        g <<= 1;
        b <<= 1;
        pR++;
        pG++;
        pB++;
    }
}
// 更新函数 ，负责将内存中的颜色数据实际发送到LED硬件上显示。
void WS2812B_Task(void)
{
   
    // 将gWs2812bDat数据解析成SPI数据
    for (uint8_t iLED = 0; iLED < WS2812B_AMOUNT; iLED++)
    {
        WS2812b_Set(iLED, gWs2812bDat[iLED].R, gWs2812bDat[iLED].G, gWs2812bDat[iLED].B);
    }
    // 总线输出数据
    HAL_SPI_Transmit(&Spi1Handle, gWs2812bDat_SPI, sizeof(gWs2812bDat_SPI), 0XFFFF);
    uint8_t dat = 0;
    // 使总线输出低电平
    HAL_SPI_Transmit(&Spi1Handle, &dat, 1, 0XFFFF);
    // 帧信号：一个大于50us的低电平
    HAL_Delay(1);
}

/**
 * @brief  通过渐变方式更新LED颜色（线性插值）
 * @param  target_colors: 目标颜色数组
 * @param  steps: 渐变步数
 * @param  delay_ms: 每步之间的延迟时间（毫秒）
 */
void ws2812_gradient(tWs2812bCache_TypeDef target_colors[], uint8_t steps, uint16_t delay_ms)
{
    static uint8_t start_r[WS2812B_AMOUNT], start_g[WS2812B_AMOUNT], start_b[WS2812B_AMOUNT];
    static float r_step[WS2812B_AMOUNT], g_step[WS2812B_AMOUNT], b_step[WS2812B_AMOUNT];

    // 保存当前颜色作为起始颜色，并计算每步的渐变步长
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
    {
        start_r[i] = gWs2812bDat[i].R;
        start_g[i] = gWs2812bDat[i].G;
        start_b[i] = gWs2812bDat[i].B;

        r_step[i] = (float)(target_colors[i].R - start_r[i]) / steps;
        g_step[i] = (float)(target_colors[i].G - start_g[i]) / steps;
        b_step[i] = (float)(target_colors[i].B - start_b[i]) / steps;
    }

    // 逐步渐变
    for (uint8_t step = 1; step <= steps; step++)
    {
        for (uint8_t led_id = 0; led_id < WS2812B_AMOUNT; led_id++)
        {
            // 计算当前步的颜色
            uint8_t r = (uint8_t)(start_r[led_id] + r_step[led_id] * step);
            uint8_t g = (uint8_t)(start_g[led_id] + g_step[led_id] * step);
            uint8_t b = (uint8_t)(start_b[led_id] + b_step[led_id] * step);

            gWs2812bDat[led_id].R = r;
            gWs2812bDat[led_id].G = g;
            gWs2812bDat[led_id].B = b;
        }

        WS2812B_Task();
        HAL_Delay(delay_ms);
    }
}

/**
 * @brief  彩虹渐变效果
 * @param  steps: 每个颜色的中间过渡色
 * @param  delay_ms: 每步之间的延迟时间（毫秒）
 */
void rainbow_gradient(uint8_t steps, uint16_t delay_ms)
{
    for (uint8_t phase = 0; phase < 255; phase += 5)
    {
        for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
        {
            // 计算每个LED的色相偏移
            uint8_t hue = (phase + (i * 255 / WS2812B_AMOUNT)) % 255;

            // 简化的HSV到RGB转换（只使用色相，饱和度和亮度固定）
            uint8_t r, g, b;
            if (hue < 85)
            {
                r = 255 - hue * 3;
                g = hue * 3;
                b = 0;
            }
            else if (hue < 170)
            {
                hue -= 85;
                r = 0;
                g = 255 - hue * 3;
                b = hue * 3;
            }
            else
            {
                hue -= 170;
                r = hue * 3;
                g = 0;
                b = 255 - hue * 3;
            }

            gWs2812bDat[i].R = r;
            gWs2812bDat[i].G = g;
            gWs2812bDat[i].B = b;
        }

        WS2812B_Task();
        HAL_Delay(delay_ms);
    }
}

/**
 * @brief  统一颜色渐变效果
 * @param  steps: 每个颜色的中间过渡色
 * @param  delay_ms: 每步之间的延迟时间（毫秒）
 */
void uniform_gradient(uint8_t steps, uint16_t delay_ms)
{
    //定义一个二维数组，7行3列
    uint8_t colors[][3] = {
        {255, 0, 0},    // 红色
        {0, 255, 0},    // 绿色
        {0, 0, 255},    // 蓝色
        {255, 255, 0},  // 黄色
        {0, 255, 255},  // 青色
        {255, 0, 255},  // 紫色
        {255, 255, 255} // 白色
    };
                                                //第一行
    uint8_t num_colors = sizeof(colors) / sizeof(colors[0]); // 计算colors颜色数组有多少行，即有多少个颜色点，7行

    for (uint8_t color_idx = 0; color_idx < num_colors; color_idx++) // 循环遍历所有关键颜色，每次处理从当前颜色到下一个颜色的渐变
    {                               //1-7
        uint8_t next_color_idx = (color_idx + 1) % num_colors; // 使用取模运算实现颜色循环，最后一个颜色的下一个颜色是第一个颜色（0到6）,第一次1。

        // 计算颜色渐变步长,分别计算红、绿、蓝三个通道从当前颜色到下一个颜色的每步变化量
        float r_step = (float)(colors[next_color_idx][0] - colors[color_idx][0]) / steps; // 红色步长(0-255)/30 ≈ -85
        float g_step = (float)(colors[next_color_idx][1] - colors[color_idx][1]) / steps; // 绿色步长(255-0)/30 = 85
        float b_step = (float)(colors[next_color_idx][2] - colors[color_idx][2]) / steps; // 蓝色步长(0-0)/30 = 0

        //  设置个传入函数步长的循环
        for (uint8_t step = 0; step < steps; step++)
        {
            uint8_t r = (uint8_t)(colors[color_idx][0] + r_step * step); //(255+(-85)0, 0+850, 0) → (255,0,0)（红色）(255+(-85)1, 0+851, 0) → (170,85,0)（橙红色）(255+(-85)2, 0+852, 0) → (85,170,0)（黄绿色
            uint8_t g = (uint8_t)(colors[color_idx][1] + g_step * step);
            uint8_t b = (uint8_t)(colors[color_idx][2] + b_step * step);

            // 更新所有LED为相同的颜色
            for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
            {
                gWs2812bDat[i].R = r;
                gWs2812bDat[i].G = g;
                gWs2812bDat[i].B = b;
            }

            WS2812B_Task();
            HAL_Delay(delay_ms);
        }
    }
}

/**
 * @brief  彗星效果
 * @param  tail_length: 彗星尾巴长度
 * @param  brightness: 彗星头部亮度（0-255）
 * @param  delay_ms: 移动延迟时间（毫秒）
 */
void comet_effect(uint8_t tail_length, uint8_t brightness, uint16_t delay_ms)
{
    uint8_t colors[][3] = {
        {255, 0, 0},    // 红色
        {0, 255, 0},    // 绿色
        {0, 0, 255},    // 蓝色
        {255, 255, 0},  // 黄色
        {0, 255, 255},  // 青色
        {255, 0, 255},  // 紫色
        {255, 255, 255} // 白色
    };                                      // 第一行
    uint8_t num_colors = sizeof(colors) / sizeof(colors[0]); // 计算colors颜色数组有多少行，即有多少个颜色点，7行

    for (uint8_t color_idx = 0; color_idx < num_colors; color_idx++) // 循环遍历 7 种颜色，每种颜色都会生成一次完整的彗星效果
    {
        // 清除所有LED
        for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
        {
            gWs2812bDat[i].R = 0;
            gWs2812bDat[i].G = 0;
            gWs2812bDat[i].B = 0;
        }

        // 彗星从左到右移动head表示彗星头部的位置
        //从 - tail_length开始（初始时彗星完全在灯带左侧外面），逐渐移动到灯带最右侧（WS2812B_AMOUNT - 1）
         for (int16_t head = -tail_length; head < WS2812B_AMOUNT; head++)
        {
            // 更新彗星头部和尾部
            // 计算并设置彗星头部到尾部的每个 LED 的颜色和亮度：
            /*首先i从head=-10，到head-tail_length=-20结束，但i >= 0不成立，故不执行任何 LED 设置。
            */
            for (int16_t i = head; i > head - tail_length && i >= 0; i--)
            {
                //当i=head等于0，头部进入灯带第 0 个 LED
                 if (i < WS2812B_AMOUNT)
                {
                    // 计算尾部渐变亮度
                    // fade_ratio = (0-0)/10 = 0 → 亮度led_brightness=255*(1-0)=255（最亮）。
                    /*  尾部更新循环：i从1到1-3=-2，有效i=1、0：
                        i=1（头部）：fade_ratio=0 → 亮度 255 → RGB (255,0,0)。
                        i=0（尾部）：fade_ratio=(1-0)/10=0.1 → 亮度255*(0.9)=230 → RGB (230,0,0)（稍暗红色）。*/
                    float fade_ratio = (float)(head - i) / tail_length;
                    uint8_t led_brightness = (uint8_t)(brightness * (1.0f - fade_ratio));
                    /*
                    头部（i=head）：fade_ratio=0 → 亮度为brightness（最亮）
                    尾部（i=head-tail_length+1）：fade_ratio≈1 → 亮度接近 0（最暗）
                    中间部分：亮度从头部到尾部逐渐降低*/
                    /*根据计算出的亮度，调整当前颜色的 RGB 值（亮度越低，颜色越暗）*/
                    gWs2812bDat[i].R = (uint8_t)((float)colors[color_idx][0] * led_brightness / 255);//设置为是
                    gWs2812bDat[i].G = (uint8_t)((float)colors[color_idx][1] * led_brightness / 255);
                    gWs2812bDat[i].B = (uint8_t)((float)colors[color_idx][2] * led_brightness / 255);
                }
            }

            // 清除彗星尾部
            /*当彗星移动时，将超出尾部长度的 LED 熄灭，避免彗星拖出多余的残影*/
            /*当head=10时，head-tail_length=0（即 LED0）LED0 已经超出尾部范围，需要被清除*/
            if (head - tail_length >= 0 && head - tail_length < WS2812B_AMOUNT)
            {
                gWs2812bDat[head - tail_length].R = 0;
                gWs2812bDat[head - tail_length].G = 0;
                gWs2812bDat[head - tail_length].B = 0;
            }

            WS2812B_Task();
            HAL_Delay(delay_ms);
        }
    }
}
